package no.rmz.chez.evaluators;

import java.util.Map.Entry;
import no.rmz.chez.chess.board.ChessBoard;
import no.rmz.chez.chess.board.Color;
import no.rmz.chez.chess.board.Coord;
import no.rmz.chez.chess.pieces.Bishop;
import no.rmz.chez.chess.pieces.ChessPiece;
import no.rmz.chez.chess.pieces.King;
import no.rmz.chez.chess.pieces.Knight;
import no.rmz.chez.chess.pieces.Pawn;
import no.rmz.chez.chess.pieces.Queen;
import no.rmz.chez.chess.pieces.Rook;

/**
 * A fancy evaluator based on ideas found in http://www.chessbin.com/post/Chess-Board-Evaluation.aspx
 */
public class FancyEvaluator extends BoardEvaluator {

    // Values of pieces
    public static int pieceValue(final ChessPiece p) {
        if (p instanceof Pawn) {
            return 100;
        }
        if (p instanceof Knight) {
            return 320;
        }
        if (p instanceof Bishop) {
            return 325;
        }
        if (p instanceof Rook) {
            return 500;
        }
        if (p instanceof Queen) {
            return 975;
        }
        if (p instanceof King) {
            return 32767;
        }
        throw new IllegalArgumentException("Unknown kind of chesspiece " + p);
    }

    
    private final  static short[] pawnTable = new short[]{
        0, 0, 0, 0, 0, 0, 0, 0,
        50, 50, 50, 50, 50, 50, 50, 50,
        10, 10, 20, 30, 30, 20, 10, 10,
        5, 5, 10, 27, 27, 10, 5, 5,
        0, 0, 0, 25, 25, 0, 0, 0,
        5, -5, -10, 0, 0, -10, -5, 5,
        5, 10, 10, -25, -25, 10, 10, 5,
        0, 0, 0, 0, 0, 0, 0, 0
    };
    private final static short[] knightTable = new short[]{
        -50, -40, -30, -30, -30, -30, -40, -50,
        -40, -20, 0, 0, 0, 0, -20, -40,
        -30, 0, 10, 15, 15, 10, 0, -30,
        -30, 5, 15, 20, 20, 15, 5, -30,
        -30, 0, 15, 20, 20, 15, 0, -30,
        -30, 5, 10, 15, 15, 10, 5, -30,
        -40, -20, 0, 5, 5, 0, -20, -40,
        -50, -40, -20, -30, -30, -20, -40, -50,};
    private final static short[] bishopTable = new short[]{
        -20, -10, -10, -10, -10, -10, -10, -20,
        -10, 0, 0, 0, 0, 0, 0, -10,
        -10, 0, 5, 10, 10, 5, 0, -10,
        -10, 5, 5, 10, 10, 5, 5, -10,
        -10, 0, 10, 10, 10, 10, 0, -10,
        -10, 10, 10, 10, 10, 10, 10, -10,
        -10, 5, 0, 0, 0, 0, 5, -10,
        -20, -10, -40, -10, -10, -40, -10, -20,};
    private  final static short[] kingTable = new short[]{
        -30, -40, -40, -50, -50, -40, -40, -30,
        -30, -40, -40, -50, -50, -40, -40, -30,
        -30, -40, -40, -50, -50, -40, -40, -30,
        -30, -40, -40, -50, -50, -40, -40, -30,
        -20, -30, -30, -40, -40, -30, -30, -20,
        -10, -20, -20, -20, -20, -20, -20, -10,
        20, 20, 0, 0, 0, 0, 20, 20,
        20, 30, 10, 0, 0, 10, 30, 20
    };
    private final static short[] kingTableEndGame = new short[]{
        -50, -40, -30, -20, -20, -30, -40, -50,
        -30, -20, -10, 0, 0, -10, -20, -30,
        -30, -10, 20, 30, 30, 20, -10, -30,
        -30, -10, 30, 40, 40, 30, -10, -30,
        -30, -10, 30, 40, 40, 30, -10, -30,
        -30, -10, 20, 30, 30, 20, -10, -30,
        -30, -30, 0, 0, 0, 0, -30, -30,
        -50, -30, -30, -30, -30, -30, -30, -50
    };

    private FancyEvaluator() {

    }
    
    final private static FancyEvaluator instance = new FancyEvaluator();

    public static BoardEvaluator getInstance() {
        return instance;
    }

    private short[] getPosTable(final ChessPiece p, boolean endgame) {
       if (p instanceof Pawn) {
            return pawnTable;
        }
        if (p instanceof Knight) {
            return knightTable;
        }
        if (p instanceof Bishop) {
            return bishopTable;
        }
        if (p instanceof Rook) {
            return knightTable; // THe origial text didn't give a rooktable
        }
        if (p instanceof Queen) {
            return kingTable;  // XX The original had no table for queens
        }
        if (p instanceof King) {
            if (endgame) {
                return kingTableEndGame;
            } else {
                return kingTable;
           }
        }
        throw new IllegalArgumentException("Unknown kind of chesspiece " + p);
    }



    @Override
    public double evaluate(final ChessBoard b, final Color c) {
        double result = 0;
        for(final Entry<Coord, ChessPiece> entry: b.getPiecesMap().entrySet()) {
            final ChessPiece piece = entry.getValue();
            final Coord      coord = entry.getKey();
            result += c.colsign(piece.getColor()) * (pieceValue(piece) + posValue(piece, coord));
        }
        return result;
    }

    private int posValue(ChessPiece piece, Coord coord) {
        return getPosTable(piece, false)[coord.asIndex()];
    }

// (from the webside referred to above): We declare a single variable representing the score for the current chess piece.
// This score will always start at 0 and go up if the position is evaluated to be
// better, and go down if the position is evaluated to be worse.  When
// the score is returned to the main Evaluation Function, it will be
// subtracted for black and added for white.

}
